home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr26 / netprog.zip / NETPROG.TAR / rlogin / rlogind.c < prev    next >
C/C++ Source or Header  |  1989-12-17  |  26KB  |  1,021 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. char copyright[] =
  20. "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\
  21.  All rights reserved.\n";
  22. #endif /* not lint */
  23.  
  24. #ifndef lint
  25. static char sccsid[] = "@(#)rlogind.c    5.22.1.6 (Berkeley) 2/7/89";
  26. #endif /* not lint */
  27.  
  28. /*
  29.  * remote login server:  the following data is sent across the network
  30.  * connection by the rcmd() function that the rlogin client uses:
  31.  *    \0  (there is no auxiliary port used by the client and server)
  32.  *    client-user-name\0
  33.  *    server-user-name\0
  34.  *    terminal-type/speed\0
  35.  *    data
  36.  *
  37.  * Define OLD_LOGIN for compatibility with the 4.2BSD and 4.3BSD /bin/login.
  38.  * If this isn't defined, a newer protocol is used whereby rlogind does
  39.  * the user verification.  This only works if your /bin/login supports the
  40.  * -f and -h flags.  This newer version of login is on the Berkeley
  41.  * Networking Release 1.0 tape.
  42.  */
  43.  
  44. #ifndef    OLD_LOGIN
  45. #define    NEW_LOGIN    /* make the #ifdefs easier to understand */
  46. #endif
  47.  
  48. #include <stdio.h>
  49. #include <sys/param.h>
  50. #include <sys/stat.h>
  51. #include <sys/socket.h>
  52. #include <sys/wait.h>
  53. #include <sys/file.h>
  54.  
  55. #include <netinet/in.h>
  56.  
  57. #include <pwd.h>
  58. #include <signal.h>
  59. #include <sgtty.h>
  60. #include <stdio.h>
  61. #include <netdb.h>
  62. #include <syslog.h>
  63. #include <strings.h>
  64. #include <errno.h>
  65. extern int    errno;
  66.  
  67. /*
  68.  * We send a TIOCPKT_WINDOW notification to the client when we start up.
  69.  * This tells the client that we support the window-size-change protocol.
  70.  * The value for this (0x80) can't overlap the kernel defined TIOCKPT_xxx
  71.  * values.
  72.  */
  73.  
  74. #ifndef TIOCPKT_WINDOW
  75. #define TIOCPKT_WINDOW 0x80
  76. #endif
  77.  
  78. char        *env[2];        /* the environment we build */
  79. static char    term[64] = "TERM=";
  80. #define    ENVSIZE    (sizeof("TERM=")-1)    /* skip null for concatenation */
  81.  
  82. #define    NMAX 30
  83. char        cliuname[NMAX+1];    /* user name on client's host */
  84. char        servuname[NMAX+1];    /* user name on server's host */
  85.  
  86. int        keepalive = 1;        /* set to 0 with -n flag */
  87.  
  88. #define    SUPERUSER(pwd)    ((pwd)->pw_uid == 0)
  89.  
  90. int        reapchild();
  91. struct passwd    *getpwnam(), *pwd;
  92. char        *malloc();
  93. int        one = 1;        /* for setsockopt() */
  94.  
  95. main(argc, argv)
  96. int    argc;
  97. char    **argv;
  98. {
  99.     extern int        opterr, optind;
  100.     int            ch, addrlen;
  101.     struct sockaddr_in    cli_addr;
  102.  
  103.     openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
  104.  
  105.     opterr = 0;
  106.     while ( (ch = getopt(argc, argv, "ln")) != EOF)
  107.         switch (ch) {
  108.         case 'l':
  109. #ifdef    NEW_LOGIN
  110.             {
  111.             extern int    _check_rhosts_file;
  112.  
  113.             _check_rhosts_file = 0;    /* don't check .rhosts file */
  114.             }
  115. #endif
  116.             break;
  117.  
  118.         case 'n':
  119.             keepalive = 0;        /* don't enable SO_KEEPALIVE */
  120.             break;
  121.  
  122.         case '?':
  123.         default:
  124.             syslog(LOG_ERR, "usage: rlogind [-l] [-n]");
  125.             break;
  126.         }
  127.  
  128.     argc -= optind;
  129.     argv += optind;
  130.  
  131.     /*
  132.      * We assume we're invoked by inetd, so the socket that the connection
  133.      * is on, is open on descriptors 0, 1 and 2.
  134.      *
  135.      * First get the Internet address of the client process.
  136.      * This is required for all the authentication we perform.
  137.      */
  138.  
  139.     addrlen = sizeof(cli_addr);
  140.     if (getpeername(0, &cli_addr, &addrlen) < 0) {
  141.         syslog(LOG_ERR, "Couldn't get peer name of remote host: %m");
  142.         fatalperror("Can't get peer name of host");
  143.     }
  144.  
  145.     if (keepalive &&
  146.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
  147.                                    sizeof(one)) < 0)
  148.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  149.  
  150.     doit(&cli_addr);
  151. }
  152.  
  153. int        child;
  154. int        cleanup();
  155. char        *line;
  156. extern char    *inet_ntoa();
  157.  
  158. struct winsize    win = { 0, 0, 0, 0 };
  159.  
  160. doit(cli_addrp)
  161. struct sockaddr_in    *cli_addrp;    /* client's Internet address */
  162. {
  163.     int            i, masterfd, slavefd, childpid;
  164. #ifdef    NEW_LOGIN
  165.     int            authenticated = 0, hostok = 0;
  166.     char            remotehost[2 * MAXHOSTNAMELEN + 1];
  167. #endif
  168.     register struct hostent    *hp;
  169.     struct hostent        hostent;
  170.     char            c;
  171.  
  172.     /*
  173.      * Read the null byte from the client.  This byte is really
  174.      * written by the rcmd() function as the secondary port number.
  175.      * However, the rlogin client calls rcmd() specifying a secondary
  176.      * port of 0, so all that rcmd() sends is the null byte.
  177.      * We set a timer of 60 seconds to do this read, else we assume
  178.      * something is wrong.
  179.      */
  180.  
  181.     alarm(60);
  182.     read(0, &c, 1);
  183.     if (c != 0)
  184.         exit(1);
  185.     alarm(0);
  186.  
  187.     /*
  188.      * Try to look up the client's name, given its internet
  189.      * address, since we use the name for the authentication.
  190.      */
  191.  
  192.     cli_addrp->sin_port = ntohs((u_short)cli_addrp->sin_port);
  193.     hp = gethostbyaddr(&cli_addrp->sin_addr, sizeof(struct in_addr),
  194.                             cli_addrp->sin_family);
  195.     if (hp == NULL) {
  196.         /*
  197.          * Couldn't find the client's name.
  198.          * Use its dotted-decimal address as its name.
  199.          */
  200.  
  201.         hp = &hostent;
  202.         hp->h_name = inet_ntoa(cli_addrp->sin_addr);
  203. #ifdef    NEW_LOGIN
  204.         hostok++;
  205. #endif
  206.     }
  207. #ifdef    NEW_LOGIN
  208.       else if (local_domain(hp->h_name)) {
  209.         /*
  210.          * If the name returned by gethostbyaddr() is in our domain,
  211.          * attempt to verify that we haven't been fooled by someone
  212.          * in a remote net.  Look up the name and check that this
  213.          * address corresponds to the name.
  214.          */
  215.  
  216.         strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
  217.         remotehost[sizeof(remotehost) - 1] = 0;
  218.         if ( (hp = gethostbyname(remotehost)) != NULL) {
  219.             for ( ; hp->h_addr_list[0]; hp->h_addr_list++) {
  220.                 if (bcmp(hp->h_addr_list[0],
  221.                      (caddr_t)&cli_addrp->sin_addr,
  222.                          sizeof(cli_addrp->sin_addr)) == 0) {
  223.                     hostok++;    /* equal, OK */
  224.                     break;
  225.                 }
  226.             }
  227.         }
  228.     } else
  229.         hostok++;
  230. #endif
  231.  
  232.     /*
  233.      * Verify that the client's address is an internet address and
  234.      * that it was bound to a reserved port.
  235.      */
  236.  
  237.     if (cli_addrp->sin_family != AF_INET ||
  238.         cli_addrp->sin_port >= IPPORT_RESERVED ||
  239.         cli_addrp->sin_port <  IPPORT_RESERVED/2) {
  240.         syslog(LOG_NOTICE, "Connection from %s on illegal port",
  241.                     inet_ntoa(cli_addrp->sin_addr));
  242.         fatal(0, "Permission denied");
  243.     }
  244.  
  245. #ifdef IP_OPTIONS
  246.     {
  247.     u_char         optbuf[BUFSIZ/3], *optptr;
  248.     char         lbuf[BUFSIZ], *lptr;
  249.     int         optsize, ipproto;
  250.     struct protoent    *ip;
  251.  
  252.     if ( (ip = getprotobyname("ip")) != NULL)
  253.         ipproto = ip->p_proto;
  254.     else
  255.         ipproto = IPPROTO_IP;
  256.  
  257.     optsize = sizeof(optbuf);
  258.     if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 &&
  259.         optsize != 0) {
  260.         /*
  261.          * The client has set IP options.  This isn't allowed.
  262.          * Use syslog() to record the fact.
  263.          */
  264.  
  265.         lptr = lbuf;
  266.         optptr = optbuf;
  267.         for ( ; optsize > 0; optptr++, optsize--, lptr += 3)
  268.             sprintf(lptr, " %2.2x", *optptr);
  269.                 /* print each option byte as 3 ASCII chars */
  270.         syslog(LOG_NOTICE,
  271.             "Connection received using IP options (ignored): %s", lbuf);
  272.  
  273.         /*
  274.          * Turn off the options.  If this doesn't work, we quit.
  275.          */
  276.  
  277.         if (setsockopt(0, ipproto, IP_OPTIONS,
  278.                         (char *) NULL, &optsize) != 0) {
  279.             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
  280.             exit(1);
  281.         }
  282.     }
  283.     }
  284. #endif    /* IP_OPTIONS */
  285.  
  286.     /*
  287.      * Write a null byte back to the client telling it that
  288.      * everything is OK.  Note that this is different from the
  289.      * sequence performed by rshd.  The rshd server first reads
  290.      * the 3 strings on the socket before writing back the null
  291.      * byte if all is OK.  We can get away with this, since we're
  292.      * using a full-duplex socket.
  293.      */
  294.  
  295.     write(0, "", 1);
  296.  
  297. #ifdef    NEW_LOGIN
  298.     if (do_rlogin(hp->h_name) == 0) {
  299.         if (hostok)
  300.             authenticated++;
  301.         else
  302.             write(0, "rlogind: Host address mismatch.\r\n",
  303.                    sizeof("rlogind: Host address mismatch.\r\n") - 1);
  304.     }
  305. #endif
  306.  
  307.     /*
  308.      * Allocate and open a master pseudo-terminal.
  309.      */
  310.  
  311.     for (c = 'p'; c <= 's'; c++) {
  312.         struct stat    statbuff;
  313.  
  314.         line = "/dev/ptyXY";
  315.         line[8] = c;            /* X = [pqrs] */
  316.         line[9] = '0';            /* Y = 0 */
  317.  
  318.         if (stat(line, &statbuff) < 0)
  319.             break;
  320.  
  321.         for (i = 0; i < 16; i++) {
  322.             line[9] = "0123456789abcdef"[i];
  323.             if ( (masterfd = open(line, O_RDWR)) > 0)
  324.                 goto gotpty;    /* got the master ptr */
  325.         }
  326.     }
  327.     fatal(0, "Out of ptys");
  328.     /*NOTREACHED*/
  329.  
  330. gotpty:
  331.     ioctl(masterfd, TIOCSWINSZ, &win);    /* set window sizes all to 0 */
  332.  
  333.     /*
  334.      * Now open the slave pseudo-terminal corresponding to the
  335.      * master that we opened above.
  336.      */
  337.  
  338.     line[5] = 't';        /* change "/dev/ptyXY" to "/dev/ttyXY" */
  339.     if ( (slavefd = open(line, O_RDWR)) < 0)
  340.         fatalperror(0, line);
  341.     if (fchmod(slavefd, 0))
  342.         fatalperror(0, line);
  343.  
  344.     /*
  345.      * The 4.3BSD vhangup() system call does a virtual hangup on the
  346.      * current control terminal.  It goes through the kernel's tables
  347.      * and for every reference it finds to the current control terminal,
  348.      * it revokes that reference (i.e., unconnects any former processes
  349.      * that may have had this terminal as their control terminal).
  350.      * vhangup() also sends a SIGHUP to the process group of the control
  351.      * terminal, so we ignore this signal.
  352.      */
  353.  
  354.     signal(SIGHUP, SIG_IGN);
  355.     vhangup();
  356.     signal(SIGHUP, SIG_DFL);
  357.  
  358.     /*
  359.      * Now reopen the slave pseudo-terminal again and set it's mode.
  360.      * This gives us a "clean" control terminal.
  361.      * line[] contains the string "/dev/ttyXY" which will be used
  362.      * by the cleanup() function when we're done.
  363.      */
  364.  
  365.     if ( (slavefd = open(line, O_RDWR)) < 0)
  366.         fatalperror(0, line);
  367.  
  368.     setup_term(slavefd);
  369.  
  370. #ifdef DEBUG
  371.     {
  372.         int    tt;
  373.  
  374.         if ( (tt = open("/dev/tty", O_RDWR)) > 0) {
  375.             ioctl(tt, TIOCNOTTY, 0);
  376.             close(tt);
  377.         }
  378.     }
  379. #endif
  380.  
  381.     if ( (childpid = fork()) < 0)
  382.         fatalperror(0, "");
  383.  
  384.     if (childpid == 0) {
  385.         /*
  386.          * Child process.  Becomes the login shell for the user.
  387.          */
  388.  
  389.         close(0);        /* close socket */
  390.         close(masterfd);    /* close pty master */
  391.         dup2(slavefd, 0);    /* pty slave is 0,1,2 of login shell */
  392.         dup2(slavefd, 1);
  393.         dup2(slavefd, 2);
  394.         close(slavefd);
  395.  
  396. #ifdef OLD_LOGIN
  397.         /*
  398.          * Invoke /bin/login with the -r argument, which tells
  399.          * it was invoked by rlogind.  This causes login to read the
  400.          * the socket for the client-user-name, the server-user-name
  401.          * and the terminal-type/speed.  login then calls the
  402.          * ruserok() function and possibly prompts the client for
  403.          * their password.
  404.          */
  405.  
  406.         execl("/bin/login", "login", "-r", hp->h_name, (char *) 0);
  407.  
  408. #else /* NEW_LOGIN */
  409.         /*
  410.          * The -p flag tells login not to destroy the environment.
  411.          * The -h flag passes the name of the client's system to
  412.          * login, so it can be placed in the utmp and wtmp entries.
  413.          * The -f flag says the user has already been authenticated.
  414.          */
  415.  
  416.         if (authenticated)
  417.             execl("/bin/login", "login", "-p", "-h", hp->h_name,
  418.                 "-f", servuname, (char *) 0);
  419.         else
  420.             execl("/bin/login", "login", "-p", "-h", hp->h_name,
  421.                 servuname, (char *) 0);
  422. #endif /* OLD_LOGIN */
  423.  
  424.         fatalperror(2, "/bin/login");    /* exec error */
  425.         /*NOTREACHED*/
  426.     }
  427.  
  428.     /*
  429.      * Parent process.
  430.      */
  431.  
  432.     close(slavefd);            /* close slave pty, child uses it */
  433.  
  434.     ioctl(0, FIONBIO, &one);    /* nonblocking I/O for socket */
  435.     ioctl(masterfd, FIONBIO, &one);    /* nonblocking I/O for master pty */
  436.     ioctl(masterfd, TIOCPKT, &one);    /* BSD pty packet mode */
  437.  
  438.     signal(SIGTSTP, SIG_IGN);
  439.     signal(SIGCHLD, cleanup);
  440.  
  441.     setpgrp(0, 0);            /* set our process group to 0 */
  442.  
  443.     protocol(0, masterfd);        /* this does it all */
  444.  
  445.     signal(SIGCHLD, SIG_IGN);
  446.     cleanup();
  447. }
  448.  
  449. /*
  450.  * Define the pty packet-mode control bytes that we're interested in.
  451.  * We ignore any other of the control bytes.
  452.  */
  453.  
  454. #define    pkcontrol(c)    ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
  455.  
  456. /*
  457.  * The following byte always gets sent along with the pty packet-mode
  458.  * control byte to the client.  It's initialized to TIOCPKT_WINDOW
  459.  * but this bit gets turned off after the client has sent the first
  460.  * window size.  Thereafter this byte is 0.
  461.  */
  462.  
  463. char    oobdata[] = {TIOCPKT_WINDOW};
  464.  
  465. /*
  466.  * Handle an in-band control request from the client.
  467.  * These are signaled by two consecutive magic[] bytes appearing in
  468.  * the data from the client.  The next two bytes in the data stream
  469.  * tell us what type of control message this is.
  470.  * For now, all we handle is a window-size-change.
  471.  *
  472.  * We return the number of bytes that we processed in the buffer, so that
  473.  * the caller can skip over them.
  474.  */
  475.  
  476. char    magic[2] = { 0377, 0377 };    /* in-band magic cookie */
  477.  
  478. int
  479. control(pty, cp, n)
  480. int    pty;        /* fd of pty master */
  481. char    *cp;        /* pointer to first two bytes of control sequence */
  482. int    n;
  483. {
  484.     struct winsize    w;
  485.  
  486.     if (n < 4+sizeof(w) || cp[2] != 's' || cp[3] != 's')
  487.         return (0);
  488.  
  489.     /*
  490.      * Once we receive one of these in-band control requests from
  491.      * the client we know that it received the TIOCPKT_WINDOW
  492.      * message that we sent it on startup.  We only send this
  493.      * control byte at the beginning, to tell the client that we
  494.      * support window-size-changes.  Now we can turn off the
  495.      * TIOCPKT_WINDOW bit in our control byte.
  496.      */
  497.  
  498.     oobdata[0] &= ~TIOCPKT_WINDOW;
  499.  
  500.     bcopy(cp+4, (char *) &w, sizeof(w));    /* copy into structure */
  501.     w.ws_row    = ntohs(w.ws_row);    /* and change to host byte order */
  502.     w.ws_col    = ntohs(w.ws_col);
  503.     w.ws_xpixel = ntohs(w.ws_xpixel);
  504.     w.ws_ypixel = ntohs(w.ws_ypixel);
  505.     ioctl(pty, TIOCSWINSZ, &w);        /* set the new window size */
  506.  
  507.     return (4 + sizeof(w));
  508. }
  509.  
  510. /*
  511.  * rlogin server "protocol" machine.
  512.  *
  513.  * The only condition for which we return to the caller is if we get an
  514.  * error or EOF on the network connection.
  515.  */
  516.  
  517. protocol(socketfd, masterfd)
  518. int    socketfd;    /* network connection to client */
  519. int    masterfd;    /* master pseudo-terminal */
  520. {
  521.     char        mptyibuf[1024], sockibuf[1024], *mptybptr, *sockbptr;
  522.     register int    mptycc, sockcc;
  523.     int        cc, maxfdp1;
  524.     int        mptymask, sockmask;
  525.     char        cntlbyte;
  526.  
  527.     mptycc = 0;        /* count of #bytes in buffer */
  528.     sockcc = 0;
  529.  
  530.     /*
  531.      * We must ignore SIGTTOU, otherwise we'll stop when we try
  532.      * and set the slave pty's window size (our controlling tty
  533.      * is the master pty).
  534.      */
  535.  
  536.     signal(SIGTTOU, SIG_IGN);
  537.  
  538.     /*
  539.      * Send the TIOCPKT_WINDOW control byte to the client
  540.      * (as an OOB data byte) telling it that we'll accept
  541.      * window-size changes.
  542.      */
  543.  
  544.     send(socketfd, oobdata, 1, MSG_OOB);
  545.  
  546.     /*
  547.      * Set things up for the calls to select().
  548.      * We cheat and store the file descriptor masks in an int,
  549.      * knowing that they can't exceed 32 (or something else is wrong).
  550.      */
  551.  
  552.     if (socketfd > masterfd)    /* determine max descriptor */
  553.         maxfdp1 = socketfd + 1;
  554.     else
  555.         maxfdp1 = masterfd + 1;
  556.  
  557.     sockmask = 1 << socketfd;    /* select mask for this descriptor */
  558.     mptymask = 1 << masterfd;
  559.  
  560.     /*
  561.      * This loop multiplexes the 2 I/O "streams":
  562.      *    network input -> sockibuf[]
  563.      *                     sockibuf[] -> master pty (input from client)
  564.      *
  565.      *    master pty input -> mptyibuf[]
  566.      *                        mptyibuf[] -> network (output for client)
  567.      */
  568.  
  569.     for ( ; ; ) {
  570.         int    ibits, obits, ebits;
  571.  
  572.         ibits = 0;
  573.         obits = 0;
  574.         if (sockcc)
  575.             obits |= mptymask;
  576.         else
  577.             ibits |= sockmask;
  578.         if (mptycc >= 0) {
  579.             if (mptycc)
  580.                 obits |= sockmask;
  581.             else
  582.                 ibits |= mptymask;
  583.         }
  584.         ebits = mptymask;
  585.         if (select(maxfdp1, (fd_set *) &ibits,
  586.                 obits ? (fd_set *) &obits : (fd_set *) NULL,
  587.                 (fd_set *) &ebits, (struct timeval *) 0) < 0) {
  588.             if (errno == EINTR)
  589.                 continue;
  590.             fatalperror(socketfd, "select");
  591.         }
  592.  
  593.         if (ibits == 0 && obits == 0 && ebits == 0) {
  594.             /* shouldn't happen... */
  595.             sleep(5);
  596.             continue;
  597.         }
  598.  
  599.         if ((ebits & mptymask) != 0) {
  600.             /*
  601.              * There is an exceptional condition on the master
  602.              * pty.  In the pty packet mode, this means there
  603.              * is a single TIOCPKT_xxx control byte available.
  604.              * Send that control byte to the client as OOB data.
  605.              */
  606.  
  607.             cc = read(masterfd, &cntlbyte, 1);
  608.             if (cc == 1 && pkcontrol(cntlbyte)) {
  609.                 cntlbyte |= oobdata[0];
  610.                 send(socketfd, &cntlbyte, 1, MSG_OOB);
  611.  
  612.                 if (cntlbyte & TIOCPKT_FLUSHWRITE) {
  613.                     /*
  614.                      * If the pty slave flushed its output
  615.                      * queue, then we want to throw away
  616.                      * anything we have in our buffer to
  617.                      * send to the client.
  618.                      */
  619.  
  620.                     mptycc = 0;
  621.                     ibits &= ~mptymask;
  622.                 }
  623.             }
  624.             /* else could be a packet-mode control byte that
  625.                we're not interested in */
  626.         }
  627.  
  628.         if ((ibits & sockmask) != 0) {
  629.             /*
  630.              * There is input ready on the socket from the client.
  631.              */
  632.  
  633.             sockcc = read(socketfd, sockibuf, sizeof(sockibuf));
  634.             if (sockcc < 0 && errno == EWOULDBLOCK)
  635.                 sockcc = 0;
  636.             else {
  637.                 register char    *ptr;
  638.                 int        left, n;
  639.  
  640.                 if (sockcc <= 0)
  641.                     break;
  642.                 sockbptr = sockibuf;
  643.  
  644.             top:
  645.                 for (ptr = sockibuf; ptr < sockibuf+sockcc-1;
  646.                                     ptr++) {
  647.                     if (ptr[0] == magic[0] &&
  648.                         ptr[1] == magic[1]) {
  649.                         /*
  650.                          * We have an in-band control
  651.                          * message.  Process it.  After
  652.                          * we've processed it we have to
  653.                          * move all the remaining data
  654.                          * in the buffer left, and check
  655.                          * for any more in-band control
  656.                          * messages.  Ugh.
  657.                          */
  658.  
  659.                         left = sockcc - (ptr-sockibuf);
  660.                         n = control(masterfd, ptr, left);
  661.                         if (n) {
  662.                            left -= n;
  663.                            if (left > 0)
  664.                               bcopy(ptr+n, ptr, left);
  665.                            sockcc -= n;
  666.                            goto top; /* n^2 */
  667.                         }
  668.                     }
  669.                 }
  670.                 obits |= mptymask;    /* try write */
  671.             }
  672.         }
  673.  
  674.         if ((obits & mptymask) != 0  &&  sockcc > 0) {
  675.             /*
  676.              * The master pty is ready to accept data and there
  677.              * is data from the socket to write to the mpty.
  678.              * An error from the write is not fatal, since we
  679.              * set the master pty to nonblocking and it may
  680.              * not really be ready for writing (see "try write"
  681.              * comment above).
  682.              */
  683.  
  684.             cc = write(masterfd, sockbptr, sockcc);
  685.             if (cc > 0) {
  686.                 sockcc -= cc;    /* write succeeded */
  687.                 sockbptr += cc;    /* update counter and pointer */
  688.             }
  689.         }
  690.  
  691.         if ((ibits & mptymask) != 0) {
  692.             /*
  693.              * There is input from the master pty.  Read it into
  694.              * the beginning of out "mptyibuf" buffer.
  695.              */
  696.  
  697.             mptycc = read(masterfd, mptyibuf, sizeof(mptyibuf));
  698.             mptybptr = mptyibuf;
  699.             if (mptycc < 0 && errno == EWOULDBLOCK)
  700.                 mptycc = 0;
  701.             else if (mptycc <= 0)
  702.                 break;    /* returns from function; done */
  703.             else if (mptyibuf[0] == 0) {
  704.                 /*
  705.                  * If the first byte that we read is a 0, then
  706.                  * there is real data in the buffer for us,
  707.                  * not one of the packet-mode control bytes.
  708.                  */
  709.  
  710.                 mptybptr++;    /* skip over the byte of 0 */
  711.                 mptycc--;
  712.                 obits |= sockmask;   /* try a write to socket */
  713.             } else {
  714.                 /*
  715.                  * It's possible for the master pty to generate
  716.                  * a control byte for us, between the select
  717.                  * above and the read that we just did.
  718.                  */
  719.  
  720.                 if (pkcontrol(mptyibuf[0])) {
  721.                     mptyibuf[0] |= oobdata[0];
  722.                     send(socketfd, &mptyibuf[0], 1, MSG_OOB);
  723.                 }
  724.                 /* else it has to be one of the packet-mode
  725.                    control bytes that we're not interested in */
  726.  
  727.                 mptycc = 0;    /* there can't be any data after
  728.                            the control byte */
  729.             }
  730.         }
  731.  
  732.         if ((obits & sockmask) != 0  &&  mptycc > 0) {
  733.             /*
  734.              * The socket is ready for more output and we have
  735.              * data from the master pty to send to the client.
  736.              */
  737.  
  738.             cc = write(socketfd, mptybptr, mptycc);
  739.             if (cc < 0 && errno == EWOULDBLOCK) {
  740.                 /* also shouldn't happen */
  741.                 sleep(5);
  742.                 continue;
  743.             }
  744.             if (cc > 0) {
  745.                 mptycc -= cc;    /* update counter and pointer */
  746.                 mptybptr += cc;
  747.             }
  748.         }
  749.     }
  750. }
  751.  
  752. /*
  753.  * This function is called if a SIGCLD signal occurs.  This means that our
  754.  * child, the login shell that we invoked through /bin/login, terminated.
  755.  * This function is also called at the end of the parent, which only happens
  756.  * if it gets an error or EOF on the network connection to the client.
  757.  */
  758.  
  759. cleanup()
  760. {
  761.     char    *p;
  762.  
  763.     /*
  764.      * Remove the /etc/utmp entry by calling the logout() function.
  765.      * Then add the terminating entry to the /usr/adm/wtmp file.
  766.      */
  767.  
  768.     p = line + 5;        /* p = pointer to "ttyXY" */
  769.     if (logout(p))
  770.         logwtmp(p, "", "");
  771.  
  772.     chmod(line, 0666);    /* change mode of slave to rw-rw-rw */
  773.     chown(line, 0, 0);    /* change owner=root, group-owner=wheel */
  774.  
  775.     *p = 'p';        /* change "ttyXY" to "ptyXY" */
  776.     chmod(line, 0666);    /* change mode of master to rw-rw-rw */
  777.     chown(line, 0, 0);    /* change owner=root, group-owner=wheel */
  778.  
  779.     shutdown(0, 2);        /* close both directions of socket */
  780.  
  781.     exit(1);
  782. }
  783.  
  784. /*
  785.  * Send an error message back to the rlogin client.
  786.  * The first byte must be a binary 1, followed by the ASCII
  787.  * error message, followed by a return/newline.
  788.  */
  789.  
  790. fatal(fd, msg)
  791. int    fd;
  792. char    *msg;
  793. {
  794.     char buf[BUFSIZ];
  795.  
  796.     buf[0] = 1;
  797.     sprintf(buf + 1, "rlogind: %s.\r\n", msg);
  798.     write(fd, buf, strlen(buf));
  799.     exit(1);
  800. }
  801.  
  802. /*
  803.  * Fatal error, as above, but include the errno value in the message.
  804.  */
  805.  
  806. fatalperror(fd, msg)
  807. int    fd;
  808. char    *msg;
  809. {
  810.     char        buf[BUFSIZ];
  811.     extern int    sys_nerr;
  812.     extern char    *sys_errlist[];
  813.  
  814.     if ((unsigned) errno < sys_nerr)
  815.         sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
  816.     else
  817.         sprintf(buf, "%s: Error %d", msg, errno);
  818.  
  819.     fatal(fd, buf);
  820.         /* NOTREACHED */
  821. }
  822.  
  823. #ifdef    OLD_LOGIN
  824.  
  825. /*
  826.  * Set up the slave pseudo-terminal.
  827.  * This is because the slave becomes standard input, standard output,
  828.  * and standard error of /bin/login.
  829.  * The mode of the slave's pty will be reset again by /bin/login.
  830.  */
  831.  
  832. setup_term(fd)
  833. int    fd;
  834. {
  835.     struct sgttyb    sgttyb;
  836.  
  837.     ioctl(fd, TIOCGETP, &sgttyb);
  838.     sgttyb.sg_flags = RAW | ANYP;
  839.             /* raw mode */
  840.             /* accept any parity, send none */
  841.     ioctl(fd, TIOCSETP, &sgttyb);
  842. }
  843.  
  844. #endif    /* OLD_LOGIN */
  845.  
  846. #ifdef    NEW_LOGIN
  847.  
  848. /*
  849.  * The new rlogind does the user authentication here.  In 4.2BSD & 4.3BSD
  850.  * this was done by the login program when invoked with the -r flag.
  851.  */
  852.  
  853. int            /* return 0 if user validated OK, else -1 on error */
  854. do_rlogin(host)
  855. char    *host;
  856. {
  857.     /*
  858.      * Read the 3 strings that the rcmd() function wrote to the
  859.      * socket: the client-user-name, server-user-name and
  860.      * terminal-type/speed.
  861.      */
  862.  
  863.     getstr(cliuname, sizeof(cliuname), "remuser too long");
  864.     getstr(servuname, sizeof(servuname), "locuser too long");
  865.     getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
  866.  
  867.     /*
  868.      * The real-user-ID has to be root since we're invoked by the
  869.      * inetd daemon.
  870.      */
  871.  
  872.     if (getuid())
  873.         return(-1);
  874.  
  875.     /*
  876.      * The server-user-name has to correspond to an account on
  877.      * this system.
  878.      */
  879.  
  880.     if ( (pwd = getpwnam(servuname)) == NULL)
  881.         return(-1);
  882.  
  883.     /*
  884.      * Call the ruserok() function to authenticate the client.
  885.      * This function returns 0 if OK, else -1 on error.
  886.      */
  887.  
  888.     return( ruserok(host, SUPERUSER(pwd), cliuname, servuname) );
  889. }
  890.  
  891. /*
  892.  * Read a string from the socket.  Make sure it fits, else fatal error.
  893.  */
  894.  
  895. getstr(buf, cnt, errmsg)
  896. char    *buf;        /* the string that's read goes into here */
  897. int    cnt;        /* sizeof() the char array */
  898. char    *errmsg;    /* in case error message required */
  899. {
  900.     char     c;
  901.  
  902.     do {
  903.         if (read(0, &c, 1) != 1)
  904.             exit(1);        /* error or EOF */
  905.         if (--cnt < 0)
  906.             fatal(1, errmsg);    /* no return */
  907.         *buf++ = c;
  908.     } while (c != 0);        /* null byte terminates the string */
  909. }
  910.  
  911. extern    char **environ;
  912.  
  913. char    *speeds[] = {    /* the order *IS* important - see tty(4) */
  914.     "0", "50", "75", "110", "134", "150", "200", "300", "600",
  915.     "1200", "1800", "2400", "4800", "9600", "19200", "38400",
  916. };
  917. #define    NSPEEDS    (sizeof(speeds) / sizeof(speeds[0]))
  918.  
  919. /*
  920.  * Set up the slave pseudo-terminal device.
  921.  * We take the terminal name that was sent over by the rlogin client,
  922.  * along with the speed.  We set the speed of the slave pty accordingly
  923.  * (since programs such as vi do things differently based on the user's
  924.  * terminal speed) and propagate the terminal type into the initial
  925.  * environment.
  926.  */
  927.  
  928. setup_term(fd)
  929. int    fd;
  930. {
  931.     register char    *cp, **cpp;
  932.     struct sgttyb    sgttyb;
  933.     char        *speed;
  934.  
  935.     ioctl(fd, TIOCGETP, &sgttyb);    /* fetch modes for slave pty */
  936.  
  937.     if ( (cp = index(term, '/')) != NULL) {
  938.         /*
  939.          * The rlogin client sends a string such as "vt100/9600"
  940.          * which was stored in the term[] array by do_rlogin().
  941.          */
  942.  
  943.         *cp++ = '\0';    /* null terminate the terminal name */
  944.         speed = cp;    /* and get pointer to ASCII speed */
  945.  
  946.         /*
  947.          * Assure the ASCII speed is null terminated, in case
  948.          * it's followed by another slash.  This allows the client
  949.          * to append additional things to the string, separated
  950.          * by slashes, even though we don't currently look at them.
  951.          */
  952.  
  953.         if ( (cp = index(speed, '/')) != NULL)
  954.             *cp++ = '\0';
  955.  
  956.         /*
  957.          * Compare the ASCII speed with the array above, and set
  958.          * the slave pty speed accordingly.
  959.          */
  960.  
  961.         for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) {
  962.             if (strcmp(*cpp, speed) == 0) {
  963.                 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds;
  964.                 break;
  965.             }
  966.         }
  967.     }
  968.     sgttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
  969.             /* echo on */
  970.             /* map CR into LF; output LF as CR-LF */
  971.             /* accept any parity, send none */
  972.             /* replace tabs by spaces on output */
  973.  
  974.     ioctl(fd, TIOCSETP, &sgttyb);
  975.  
  976.     /*
  977.      * Initialize the environment that we'll ask /bin/login to
  978.      * maintain.  /bin/login will then append its variables
  979.      * (HOME, SHELL, USER, PATH, ...) to this.
  980.      */
  981.  
  982.     env[0] = term;        /* the "TERM=..." string */
  983.     env[1] = (char *) 0;    /* one element is all we initialize it with */
  984.     environ = env;        /* stuff it away for our execl of /bin/login */
  985. }
  986.  
  987. /*
  988.  * Check whether the specified host is in our local domain, as determined
  989.  * by the part of the name following the first period, in its name and in ours.
  990.  * If either name is unqualified (contains no period), assume that the host
  991.  * is local, as it will be interpreted as such.
  992.  */
  993.  
  994. int                /* return 1 if local domain, else return 0 */
  995. local_domain(host)
  996. char    *host;
  997. {
  998.     register char    *ptr1, *ptr2;
  999.     char        localhost[MAXHOSTNAMELEN];
  1000.  
  1001.     if ( (ptr1 = index(host, '.')) == NULL)
  1002.         return(1);        /* no period in remote host name */
  1003.  
  1004.     gethostname(localhost, sizeof(localhost));
  1005.     if ( (ptr2 = index(localhost, '.')) == NULL)
  1006.         return(1);        /* no period in local host name */
  1007.  
  1008.     /*
  1009.      * Both host names contain a period.  Now compare both names,
  1010.      * starting with the first period in each name (i.e., the names
  1011.      * of their respective domains).  If equal, then the remote domain
  1012.      * equals the local domain, return 1.
  1013.      */
  1014.  
  1015.     if (strcasecmp(ptr1, ptr2) == 0)    /* case insensitive compare */
  1016.         return(1);
  1017.  
  1018.     return(0);
  1019. }
  1020. #endif /* NEW_LOGIN */
  1021.